#include  "wx/wxprec.h"
#include "wx/textbuf.h"

const wxTextFileType wxTextBuffer::typeDefault =
  #if defined(__WINDOWS__) || defined(__DOS__) || defined(__PALMOS__)
  wxTextFileType_Dos;
  #elif defined(__UNIX__)
  wxTextFileType_Unix;
  #elif defined(__WXMAC__)
  wxTextFileType_Mac;
  #elif defined(__OS2__)
  wxTextFileType_Os2;
  #else
  wxTextFileType_None;
#error  "wxTextBuffer: unsupported platform."
  #endif

const wxChar *wxTextBuffer::GetEOL( wxTextFileType type ) {
  switch( type ) {
    default:
      wxFAIL_MSG( wxT( "bad buffer type in wxTextBuffer::GetEOL." ) );
    case wxTextFileType_None:
      return wxEmptyString;
    case wxTextFileType_Unix:
      return wxT( "\n" );
    case wxTextFileType_Dos:
      return wxT( "\r\n" );
    case wxTextFileType_Mac:
      return wxT( "\r" );
  }
}

wxString wxTextBuffer::Translate( const wxString& text, wxTextFileType type ) {
  if( type == wxTextFileType_None ) {
    return text;
  }
  if( text.empty() ) {
    return text;
  }
  wxString eol = GetEOL( type ), result;
  result.Alloc( text.Len() );
  wxChar chLast = 0;
  for( const wxChar *pc = text.c_str(); *pc; pc++ ) {
    wxChar ch = *pc;
    switch( ch ) {
      case _T( '\n' ):
        result += eol;
        chLast = 0;
        break;
      case _T( '\r' ):
        if( chLast == _T( '\r' ) ) {
          result += eol;
        } else
        { chLast = _T( '\r' ); }
        break;
      default:
        if( chLast == _T( '\r' ) ) {
          result += eol;
          chLast = 0;
        }
        result += ch;
    }
  }
  if( chLast ) {
    result += eol;
  }
  return result;
}

#if wxUSE_TEXTBUFFER

wxString wxTextBuffer::ms_eof;

wxTextBuffer::wxTextBuffer( const wxString& strBufferName )
  : m_strBufferName( strBufferName ) {
  m_nCurLine = 0;
  m_isOpened = false;
}

wxTextBuffer::~wxTextBuffer() {
}

bool wxTextBuffer::Exists() const {
  return OnExists();
}

bool wxTextBuffer::Create( const wxString& strBufferName ) {
  m_strBufferName = strBufferName;
  return Create();
}

bool wxTextBuffer::Create() {
  wxASSERT( !m_strBufferName.empty() );
  if( Exists() ) {
    return false;
  }
  if( !OnOpen( m_strBufferName, WriteAccess ) ) {
    return false;
  }
  OnClose();
  return true;
}

bool wxTextBuffer::Open( const wxString& strBufferName, const wxMBConv& conv ) {
  m_strBufferName = strBufferName;
  return Open( conv );
}

bool wxTextBuffer::Open( const wxMBConv& conv ) {
  wxASSERT( !m_strBufferName.empty() );
  if( !OnOpen( m_strBufferName, ReadAccess ) ) {
    return false;
  }
  m_isOpened = OnRead( conv );
  OnClose();
  return m_isOpened;
}

wxTextFileType wxTextBuffer::GuessType() const {
  wxASSERT( IsOpened() );
  size_t nUnix = 0,
         nDos  = 0,
         nMac  = 0;
#define MAX_LINES_SCAN    (10)
  size_t nCount = m_aLines.Count() / 3,
         nScan =  nCount > 3 * MAX_LINES_SCAN ? MAX_LINES_SCAN : nCount / 3;
#define   AnalyseLine(n)              \
  switch ( m_aTypes[n] ) {            \
    case wxTextFileType_Unix: nUnix++; break;   \
    case wxTextFileType_Dos:  nDos++;  break;   \
    case wxTextFileType_Mac:  nMac++;  break;   \
    default: wxFAIL_MSG(_("unknown line terminator")); \
  }
  size_t n;
  for( n = 0; n < nScan; n++ )      // the beginning
  { AnalyseLine( n ); }
  for( n = ( nCount - nScan ) / 2; n < ( nCount + nScan ) / 2; n++ ) {
    AnalyseLine( n );
  }
  for( n = nCount - nScan; n < nCount; n++ ) {
    AnalyseLine( n );
  }
#undef   AnalyseLine
  if( nScan > 0 && nDos + nUnix + nMac == 0 ) {
    wxLogWarning( _( "'%s' is probably a binary buffer." ), m_strBufferName.c_str() );
  } else {
#define   GREATER_OF(t1, t2) n##t1 == n##t2 ? typeDefault               \
  : n##t1 > n##t2             \
  ? wxTextFileType_##t1   \
  : wxTextFileType_##t2
    #if !defined(__WATCOMC__) || wxCHECK_WATCOM_VERSION(1,4)
    if( nDos > nUnix ) {
      return GREATER_OF( Dos, Mac );
    } else if( nDos < nUnix ) {
      return GREATER_OF( Unix, Mac );
    } else
    { return nMac > nDos ? wxTextFileType_Mac : typeDefault; }
    #endif // __WATCOMC__
#undef    GREATER_OF
  }
  return typeDefault;
}


bool wxTextBuffer::Close() {
  Clear();
  m_isOpened = false;
  return true;
}

bool wxTextBuffer::Write( wxTextFileType typeNew, const wxMBConv& conv ) {
  return OnWrite( typeNew, conv );
}

#endif // wxUSE_TEXTBUFFER
